package com.sean.community.comtroller;

import com.qiniu.util.Auth;
import com.qiniu.util.StringMap;
import com.sean.community.annotation.LoginRequired;
import com.sean.community.entity.Comment;
import com.sean.community.entity.DiscussPost;
import com.sean.community.entity.Page;
import com.sean.community.entity.User;
import com.sean.community.service.*;
import com.sean.community.util.CommunityConstant;
import com.sean.community.util.CommunityUtil;
import com.sean.community.util.HostHolder;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 用户控制器
 */
@Controller
@RequestMapping("/user")
public class UserController implements CommunityConstant {

    private static final Logger logger = LoggerFactory.getLogger(UserController.class);

    @Value("${community.path.upload}")
    private String uploadPath;          // 上传路径

    @Value("${community.path.domain}")
    private String domain;              // 域名

    @Value("${server.servlet.context-path}")
    private String contextPath;         // 项目名

    @Value("${qiniu.key.access}")
    private String fileCloudServerAccessKey;    // 文件云服务器，用户身份认证密钥

    @Value("${qiniu.key.secret}")
    private String fileCloudServerSecretKey;    // 文件云服务器，文件加密密钥

    @Value("${qiniu.bucket.header.name}")
    private String fileCloudServerBucketName_header;   // 文件云服务器，头像空间名称

    @Value("${qiniu..bucket.header.url}")
    private String fileCloudServerBucketUrl_header;    // 文件云服务器，头像空间 url

    private UserService userService;
    private HostHolder hostHolder;
    private LikeService likeService;
    private FollowService followService;
    private DiscussPostService discussPostService;
    private CommentService commentService;

    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    @Autowired
    public void setHostHolder(HostHolder hostHolder) {
        this.hostHolder = hostHolder;
    }

    @Autowired
    public void setLikeService(LikeService likeService) {
        this.likeService = likeService;
    }

    @Autowired
    public void setFollowService(FollowService followService) {
        this.followService = followService;
    }

    @Autowired
    public void setDiscussPostService(DiscussPostService discussPostService) {
        this.discussPostService = discussPostService;
    }

    @Autowired
    public void setCommentService(CommentService commentService) {
        this.commentService = commentService;
    }

    @LoginRequired
    @RequestMapping(path = "/setting", method = RequestMethod.GET)
    public String getUserSettingPage(Model model){
        // 生成头像上传云服务器凭证
        // 生成上传文件名
        String fileName = CommunityUtil.generateUUID(); // 最好是用唯一随机，保留用户足迹，且云服务器有缓存，同名文件不会立刻更新
        // 期待相应
        StringMap policy = new StringMap();
        policy.put("returnBody", CommunityUtil.getJSONString(200));  // 客户端直传云服务器通常采用异步方式，返回 JSON
        // 生成凭证
        Auth auth = Auth.create(fileCloudServerAccessKey, fileCloudServerSecretKey);
        String uploadToken = auth.uploadToken(fileCloudServerBucketName_header, fileName, 3600, policy);
        model.addAllAttributes(new ModelMap("uploadToken", uploadToken));
        model.addAllAttributes(new ModelMap("fileName", fileName));
        return "site/setting";
    }

    // 更新头像路径 （更新为文件云服务器的路径）
    @RequestMapping(path = "/header/url", method = RequestMethod.POST)
    @ResponseBody
    public String uploadHeaderURl(String fileName){
        if(StringUtils.isBlank(fileName)){
            return CommunityUtil.getJSONString(404, "错误：文件名为空！");
        }
        String url = fileCloudServerBucketUrl_header + "/" + fileName;
        userService.updateHeader(hostHolder.getUser().getId(), url);
        return CommunityUtil.getJSONString(200, "更新头像成功");
    }

    /**
     * 上传头像，保存到服务器，更新用户头像 URL
     * @param headerImage 用户上传的新头像
     * @param model 模型
     * @return 根据上传是否成功返回视图
     */
    // 由于用户头像可以通过表单上传到云服务器，故废弃
    @Deprecated
    @LoginRequired
    @RequestMapping(path = "/upload", method = RequestMethod.POST)
    public String uploadHeader(MultipartFile headerImage, Model model){
        if(headerImage == null){
            model.addAllAttributes(new ModelMap("imageMsg", "请先选择图片！"));
            return "site/setting";
        }
        String filename = headerImage.getOriginalFilename();
        String suffix = filename.substring(filename.lastIndexOf("."));  // 得到的后缀为 .xxx
        if(StringUtils.isBlank(suffix)){
            model.addAllAttributes(new ModelMap("imageMsg", "请上传正确的图片格式！"));
            return "site/setting";
        }

        // 生成随机文件名
        filename = CommunityUtil.generateUUID() + suffix;
        // 保存路径
        File dest = new File(uploadPath + "/" + filename);
        try {
            // 存储文件
            headerImage.transferTo(dest);
        } catch (IOException e) {
            logger.error("上传文件失败" + e.getMessage());
            throw new RuntimeException("上传文件失败，服务器发送异常", e);
        }
        // 更新用户头像路径（web 路径）
        // http://127.0.0.1:8080/community/user/header/xxxxx
        User user = hostHolder.getUser();
        String headerUrl = domain + contextPath + "/user/header/" + filename;
        userService.updateHeader(user.getId(), headerUrl);
        return "redirect:/index";
    }

    /**
     * 解析用户头像
     * @param fileName 头像文件名
     * @param response 响应
     */
    // 由于用户头像可以通过表单上传到云服务器，故废弃
    @Deprecated
    @RequestMapping(path = "/header/{fileName}", method = RequestMethod.GET)
    public void getHeader(@PathVariable("fileName") String fileName, HttpServletResponse response){
        // 服务器存放文件的位置
        fileName = uploadPath + "/" + fileName;
        // 声明格式
        String suffix = fileName.substring(fileName.lastIndexOf(".") + 1);      // 得到 png
        response.setContentType("image/" + suffix);
        try(
            FileInputStream fileInputStream = new FileInputStream(fileName); // 编译器会自动添加 finally close 方法
            ServletOutputStream os = response.getOutputStream();
        ){
            // 使用缓冲区一批一批输出
            byte[] buffer = new byte[1024];
            int b = 0;
            while((b = fileInputStream.read(buffer)) != -1){
                os.write(buffer, 0, b);
            }
        } catch (IOException e) {
            logger.error("读取头像失败：" + e.getMessage());
        }
    }

    @LoginRequired
    @RequestMapping(path = "/updatePassword", method = RequestMethod.POST)
    public String updatePassword(String oldPassword, String newPassword, Model model){
        User user = hostHolder.getUser();
        Map<String, Object> map = userService.updatePassword(user.getId(), oldPassword, newPassword);
        if(map.containsKey("oldPasswordMsg") || map.containsKey("newPasswordMsg")){
            model.addAllAttributes(new ModelMap("oldPasswordMsg", map.get("oldPasswordMsg")));
            model.addAllAttributes(new ModelMap("newPasswordMsg", map.get("newPasswordMsg")));
            return "site/setting";
        }else{
            model.addAllAttributes(new ModelMap("msg", "密码修改成功，您需要重新登录!!"));
            model.addAllAttributes(new ModelMap("target", "/logout"));
            return "site/operate-result";
        }
    }

    @RequestMapping(path = "/profile/{userId}", method = RequestMethod.GET)
    public String getProfile(@PathVariable("userId") int userId, Model model){
        User user = userService.findUserById(userId);
        if(user == null){
            throw new RuntimeException("用户不存在！");
        }
        // 用户
        model.addAllAttributes(new ModelMap("user", user));
        // 点赞数量
        int likeCount = likeService.findUserLikeCount(userId);
        model.addAllAttributes(new ModelMap("likeCount", likeCount));
        // 关注数量
        long followeeCount = followService.findFolloweeCount(user.getId(), ENTITY_TYPE_USER);
        model.addAllAttributes(new ModelMap("followeeCount", followeeCount));
        // 粉丝数量
        long followerCount = followService.findFollowerCount(ENTITY_TYPE_USER, user.getId());
        model.addAllAttributes(new ModelMap("followerCount", followerCount));
        // 当前用户是否已经关注该用户
        User currentLoginUser = hostHolder.getUser();
        if(currentLoginUser == null){
            model.addAllAttributes(new ModelMap("hasFollowed", false));
        }else{
            boolean hasFollowed = followService.hasFollowed(currentLoginUser.getId(), ENTITY_TYPE_USER, user.getId());
            model.addAllAttributes(new ModelMap("hasFollowed", hasFollowed));
        }
        return "/site/profile";
    }


    /**
     * 获取指定用户帖子
     * @return 页面
     */
    @RequestMapping(path = "/profile-post/{userId}", method = RequestMethod.GET)
    public String getMyDiscussPost(@PathVariable("userId") int userId, Model model, Page page){
        User user = userService.findUserById(userId);
        if(user == null){
            throw new RuntimeException("用户不存在！");
        }
        // 设置分页信息
        page.setPath("/user/profile-post/" + userId);
        page.setLimit(10);
        final int discussPostRows = discussPostService.findDiscussPostRows(userId);
        page.setRows(discussPostRows);
        // 用户
        model.addAllAttributes(new ModelMap("user", user));
        // 帖子相关
        // 发布帖子总量
        model.addAllAttributes(new ModelMap("discussPostCount", discussPostRows));
        if(discussPostRows == 0){
            return "/site/my-post";
        }
        // 限制帖子显示内容长度
        List<DiscussPost> discussPostList = discussPostService
                .findDiscussPosts(userId, page.getOffset(), page.getLimit(), 0);
        for (DiscussPost discussPost : discussPostList) {
            if(discussPost.getContent().length() > 50){
                discussPost.setContent(discussPost.getContent().substring(0, 50) + "......");
            }
        }
        // 帖子 Vo
        List<Map<String, Object>> discussPostVoList = new ArrayList<>();
        for (DiscussPost discussPost : discussPostList) {
            Map<String, Object> map = new HashMap<>();
            map.put("discussPost", discussPost);
            map.put("likeCount", likeService.findEntityLikeCount(ENTITY_TYPE_DISCUSS_POST, discussPost.getId()));
            discussPostVoList.add(map);
        }
        model.addAllAttributes(new ModelMap("discussPostVoList", discussPostVoList));
        return "/site/my-post";
    }

    /**
     * 获取指定用户的回复
     * @return 页面
     */
    @RequestMapping(path = "/profile-reply/{userId}", method = RequestMethod.GET)
    public String getMyReply(@PathVariable("userId") int userId, Model model, Page page){
        User user = userService.findUserById(userId);
        if(user == null){
            throw new RuntimeException("用户不存在！");
        }
        // 设置分页信息
        page.setPath("/user/profile-reply/" + userId);
        page.setLimit(10);
        final int commentCount = commentService.findDiscussPostCommentCountByUser(userId);
        page.setRows(commentCount);
        // 用户
        model.addAllAttributes(new ModelMap("user", user));
        // 评论相关
        // 评论总数
        model.addAllAttributes(new ModelMap("commentCount", commentCount));
        if(commentCount == 0){
            return "site/my-reply";
        }
        // 限制评论显示内容长度
        List<Comment> commentList = commentService
                .findDiscussPostCommentByUser(userId, page.getOffset(), page.getLimit());
        for (Comment comment : commentList) {
            if(comment.getContent().length() > 50){
                comment.setContent(comment.getContent().substring(0, 50) + "......");
            }
        }
        // 评论 Vo
        List<Map<String, Object>> commentVoList = new ArrayList<>();
        for (Comment comment : commentList) {
            Map<String, Object> map = new HashMap<>();
            map.put("comment", comment);
            final DiscussPost discussPost = discussPostService.findDiscussPostById(comment.getEntityId());
            if(discussPost == null){
                throw new RuntimeException("帖子不存在！");
            }
            if(discussPost.getStatus() == DISCUSSPOST_STATUS_BLACKLIST){
                map.put("isDelete", true);
            }else{
                map.put("isDelete", false);
            }
            map.put("discussPostId", comment.getEntityId());
            map.put("discussPostTitle", discussPost.getTitle());
            commentVoList.add(map);
        }
        model.addAllAttributes(new ModelMap("commentVoList", commentVoList));
        return "site/my-reply";
    }
}
